From 1abc0a00cec5396d12d83c8725b6e33f148684c6 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 21 Mar 2005 18:04:36 +0000 Subject: [PATCH] bitkeeper revision 1.1236.1.101 (423f0cb4e4UtnlbkQsaMhXYz4hi__w) Add CMPXCHG8B support to the instruction emulator. Signed-off-by: Keir Fraser --- tools/tests/test_x86_emulator.c | 52 +++++++++++++++++++++++++- xen/arch/x86/x86_emulate.c | 61 +++++++++++++++++++++++++++++-- xen/include/asm-x86/x86_emulate.h | 21 +++++++++++ 3 files changed, 129 insertions(+), 5 deletions(-) diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c index 25a4a4bcbe..4347727488 100644 --- a/tools/tests/test_x86_emulator.c +++ b/tools/tests/test_x86_emulator.c @@ -60,15 +60,28 @@ static int cmpxchg_any( return X86EMUL_CONTINUE; } +static int cmpxchg8b_any( + unsigned long addr, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi) +{ + ((unsigned long *)addr)[0] = new_lo; + ((unsigned long *)addr)[1] = new_hi; + return X86EMUL_CONTINUE; +} + static struct x86_mem_emulator emulops = { - read_any, write_any, read_any, write_any, cmpxchg_any + read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any }; int main(int argc, char **argv) { struct xen_regs regs; - char instr[] = { 0x01, 0x08 }; /* add %ecx,(%eax) */ + char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */ unsigned int res = 0x7FFFFFFF; + u32 cmpxchg8b_res[2] = { 0x12345678, 0x87654321 }; unsigned long cr2; int rc; @@ -173,6 +186,41 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); + printf("%-40s", "Testing cmpxchg (%edi) [succeeding]..."); + instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f; + regs.eflags = 0x200; + regs.eax = cmpxchg8b_res[0]; + regs.edx = cmpxchg8b_res[1]; + regs.ebx = 0x9999AAAA; + regs.ecx = 0xCCCCFFFF; + regs.eip = (unsigned long)&instr[0]; + regs.edi = (unsigned long)cmpxchg8b_res; + cr2 = regs.edi; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (cmpxchg8b_res[0] != 0x9999AAAA) || + (cmpxchg8b_res[1] != 0xCCCCFFFF) || + ((regs.eflags&0x240) != 0x240) || + (regs.eip != (unsigned long)&instr[3]) ) + goto fail; + printf("okay\n"); + + printf("%-40s", "Testing cmpxchg (%edi) [failing]..."); + instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f; + regs.eip = (unsigned long)&instr[0]; + regs.edi = (unsigned long)cmpxchg8b_res; + cr2 = regs.edi; + rc = x86_emulate_memop(®s, cr2, &emulops, 4); + if ( (rc != 0) || + (cmpxchg8b_res[0] != 0x9999AAAA) || + (cmpxchg8b_res[1] != 0xCCCCFFFF) || + (regs.eax != 0x9999AAAA) || + (regs.edx != 0xCCCCFFFF) || + ((regs.eflags&0x240) != 0x200) || + (regs.eip != (unsigned long)&instr[3]) ) + goto fail; + printf("okay\n"); + return 0; fail: diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 833e0e48bd..0ee4bfa62d 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -181,7 +181,7 @@ static u8 twobyte_table[256] = { /* 0xB8 - 0xBF */ 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, 0, 0, 0, 0, /* 0xC0 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */ @@ -963,8 +963,63 @@ x86_emulate_memop( goto writeback; twobyte_special_insn: - /* Only prefetch instructions get here, so nothing to do. */ - dst.orig_val = dst.val; /* disable writeback */ + /* Disable writeback. */ + dst.orig_val = dst.val; + switch ( b ) + { + case 0x0d: /* GrpP (prefetch) */ + case 0x18: /* Grp16 (prefetch/nop) */ + break; + case 0xc7: /* Grp9 (cmpxchg8b) */ +#if defined(__i386__) + { + unsigned long old_lo, old_hi; + if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4)) != 0) || + ((rc = ops->read_emulated(cr2+4, &old_hi, 4)) != 0) ) + goto done; + if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) ) + { + _regs.eax = old_lo; + _regs.edx = old_hi; + _regs.eflags &= ~EFLG_ZF; + } + else if ( ops->cmpxchg8b_emulated == NULL ) + { + rc = X86EMUL_UNHANDLEABLE; + goto done; + } + else + { + if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi, + _regs.ebx, _regs.ecx)) != 0 ) + goto done; + _regs.eflags |= EFLG_ZF; + } + break; + } +#elif defined(__x86_64__) + { + unsigned long old, new; + if ( (rc = ops->read_emulated(cr2, &old, 8)) != 0 ) + goto done; + if ( ((u32)(old>>0) != (u32)_regs.eax) || + ((u32)(old>>32) != (u32)_regs.edx) ) + { + _regs.eax = (u32)(old>>0); + _regs.edx = (u32)(old>>32); + _regs.eflags &= ~EFLG_ZF; + } + else + { + new = (_regs.ecx<<32)|(u32)_regs.ebx; + if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8)) != 0 ) + goto done; + _regs.eflags |= EFLG_ZF; + } + break; + } +#endif + } goto writeback; cannot_emulate: diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h index 895e22a209..79197fed9c 100644 --- a/xen/include/asm-x86/x86_emulate.h +++ b/xen/include/asm-x86/x86_emulate.h @@ -34,6 +34,8 @@ * some out-of-band mechanism, unknown to the emulator. The memop signals * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will * then immediately bail. + * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only + * cmpxchg8b_emulated need support 8-byte accesses. */ /* Access completed successfully: continue emulation as normal. */ #define X86EMUL_CONTINUE 0 @@ -104,6 +106,25 @@ struct x86_mem_emulator unsigned long old, unsigned long new, unsigned int bytes); + + /* + * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an + * emulated/special memory area. + * @addr: [IN ] Linear address to access. + * @old: [IN ] Value expected to be current at @addr. + * @new: [IN ] Value to write to @addr. + * NOTES: + * 1. This function is only ever called when emulating a real CMPXCHG8B. + * 2. This function is *never* called on x86/64 systems. + * 2. Not defining this function (i.e., specifying NULL) is equivalent + * to defining a function that always returns X86EMUL_UNHANDLEABLE. + */ + int (*cmpxchg8b_emulated)( + unsigned long addr, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi); }; /* Standard reader/writer functions that callers may wish to use. */ -- 2.30.2